package it.unibo.refolding.pico;

import it.unibo.refolding.common.CommonThings;

import java.util.regex.Pattern;


interface HeaderMatcher {
	boolean matches();
	String group(int i);
	int groupCount();
}

public enum HeaderParserStrategy {
	JAVA_UTIL_REGEX {
		// 1.6 s for 100 headers
		@Override
		HeaderMatcher matcher(String s) {
			final java.util.regex.Matcher matcher = headerPattern.matcher(s);
			return new HeaderMatcher() {
				@Override
				public boolean matches() {
					return matcher.matches();
				}

				@Override
				public String group(int i) {
					return matcher.group(i);
				}

				@Override
				public int groupCount() {
					return matcher.groupCount();
				}
			};
		}
	}, JREGEX {
		// 1.0 s for 100 headers
		@Override
		HeaderMatcher matcher(String s) {
			final jregex.Matcher matcher = jregexHeaderPattern.matcher(s);
			return new HeaderMatcher() {
				@Override
				public boolean matches() {
					return matcher.matches();
				}

				@Override
				public String group(int i) {
					return matcher.group(i);
				}

				@Override
				public int groupCount() {
					return matcher.groupCount() - 1;
				}
			};
		}
	};
	
	abstract HeaderMatcher matcher(String s);

	static final Pattern headerPattern = Pattern.compile(
		headerPattern(), Pattern.MULTILINE | Pattern.DOTALL);
	static final jregex.Pattern jregexHeaderPattern = new jregex.Pattern(headerPattern(), "sm");

	static String headerPattern() {
		String nonNegativeIntRegex = "\\d+";
		// s means dotall; m means multiline
		String ciaoForceImageListDataOffsetDataLengthBytesPixel = "^\\\\\\*Ciao force image list$"
				+ "\\s+" + "^\\\\Data offset: (" + nonNegativeIntRegex
				+ ")$" // 40960, 49152, 57344
				+ "\\s+" + "^\\\\Data length: (" + nonNegativeIntRegex
				+ ")$" // 8192, 8192, 8192
				+ "\\s+" + "^\\\\Bytes/pixel: 2$" + ".*" + "^\\\\Spring Constant: ("
				+ CommonThings.FP_REGEX + ")$";
		String ciaoForceImageListDataOffsetDataLengthBytesPixelNoGroups = "^\\\\\\*Ciao force image list$"
				+ "\\s+"
				+ "^\\\\Data offset: "
				+ nonNegativeIntRegex
				+ "$" // 40960, 49152, 57344
				+ "\\s+"
				+ "^\\\\Data length: "
				+ nonNegativeIntRegex
				+ "$" // 8192, 8192, 8192
				+ "\\s+"
				+ "^\\\\Bytes/pixel: 2$"
				+ ".*"
				+ "^\\\\Spring Constant: "
				+ CommonThings.FP_REGEX + "$";
		String regex =  
				".*" + "^\\\\\\*Scanner list$" + ".*"
				+ "^\\\\Serial [nN]umber: (\\w+)$"
				+ ".*"
				+ "^\\\\@Sens\\. Zsens: V ("
				+ CommonThings.FP_REGEX
				+ ") nm/V$" // 54.65000 even in different days
				+ ".*"
				+ "^\\\\\\*Ciao scan list$"
				+ ".*"
				+ "^\\\\X [oO]ffset: (" + CommonThings.FP_REGEX + ") nm$"
				+ ".*"
				+ "^\\\\Strip chart : ((?:Enabled)|(?:Disabled))$"
				+ "\\s+"
				+ "^\\\\Strip [cC]hart [rR]ate: ("
				+ nonNegativeIntRegex
				+ ")$"
				+ ".*"
				+ "^\\\\@Sens\\. DeflSens: V ("
				+ CommonThings.FP_REGEX
				+ ") nm/V$" // 64.73873
				+ ".*"
				+ "^\\\\@Sens\\. (?:(?:ZSensorSens)|(?:ZPicoSens)): V ("
				+ CommonThings.FP_REGEX
				+ ") nm/V$" // 1000.000
				+ ".*"
				/*
				 * NanoScope IIIa: \@1:DeflectionLimit: V (20.00000 V/LSB) 20.00000 V
				 * NanoScope V: \@2:DeflectionLimit: V (0.0000000057 V/LSB) 24.57600 V
				 */
				+ "^\\\\@[12]:DeflectionLimit: V \\(" + CommonThings.FP_REGEX + " V/LSB\\) (" + CommonThings.FP_REGEX + ") V$"
				+ ".*"
				+ "^\\\\\\*Ciao force list$"
				+ ".*"
				+ "^\\\\Scan rate: ("
				+ CommonThings.FP_REGEX
				+ ")$"
				+ "\\s+"
				+ "^\\\\Forward vel\\.: ("
				+ CommonThings.FP_REGEX
				+ ")$" // 159.548
				+ "\\s+"
				+ "^\\\\Reverse vel\\.: ("
				+ CommonThings.FP_REGEX
				+ ")$" // 159.548
				+ ".*"
				+ "^\\\\Ramp delay: ("
				+ CommonThings.FP_REGEX
				+ ")$" // in seconds
				+ ".*"
				+ "^\\\\@Z scan start: V \\[Sens\\. Zsens\\] \\("
				+ CommonThings.FP_REGEX
				+ " V/LSB\\) +("
				+ CommonThings.FP_REGEX
				+ ") V$"
				// + "\\s+"
				// + "^\\\\@Z scan size: V \\[Sens\\. Zsens\\] \\(" +
				// CommonThings.FP_REGEX + " V/LSB\\) +(" +
				// CommonThings.FP_REGEX + ") V$" // always 15.38000
				+ ".*"
				+ ciaoForceImageListDataOffsetDataLengthBytesPixel
				+ ".*"
				+ ciaoForceImageListDataOffsetDataLengthBytesPixel
				+ ".*"
				+ "^\\\\@4:Z scale: V \\[Sens\\. Z(?:(?:Sensor)|(?:Pico))Sens\\] \\(("
				+ CommonThings.FP_REGEX
				+ ") V/LSB\\) +"
				+ CommonThings.FP_REGEX
				+ " V$" // 0.0003051758
				+ ".*"
				// Ramp size appears in fact 3 times, every time with the same
				// value. It varies linearly with the actual ramp size.
				+ "^\\\\@4:Ramp size: V \\[Sens\\. Zsens\\] \\("
				+ CommonThings.FP_REGEX
				+ " V/LSB\\) +("
				+ CommonThings.FP_REGEX
				+ ") V$"
				+ ".*"
				+ ciaoForceImageListDataOffsetDataLengthBytesPixelNoGroups
				+ ".*"
				+ "^\\\\\\*File list end$"
				;
		return regex;
	}
}
